﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MacomberMapSystem.Common.CIM;
using System.Data.Common;
using System.IO;

namespace MacomberMapSystem.Common.Internals
{
    /// <summary>
    /// This class handles database interfacing from Macomber Map System
    /// </summary>
    public static class MM_Database_Interface
    {        

        /// <summary>        
        /// Add a record to the database
        /// </summary>
        /// <param name="sConn"></param>
        /// <param name="CommandText"></param>
        /// <param name="inValues"></param>
        /// <param name="sTrans"></param>
        public static Int64 ExecuteCommand(DbConnection sConn, DbTransaction sTrans, String CommandText, params object[] inValues)
        {
            using (DbCommand sCmd = sConn.CreateCommand())
            {
                sCmd.CommandText = CommandText + "; SELECT last_insert_rowid() AS [ID]";
                sCmd.Transaction = sTrans;
                for (int a = 0; a < inValues.Length; a++)
                    if (inValues[a] is List<byte>)
                        AddParameterWithValue(sCmd, ":" + a.ToString(), (inValues[a] as List<byte>).ToArray());
                    else if (inValues[a] is List<UInt16>)
                    {
                        List<UInt16> OutShort = inValues[a] as List<UInt16>;
                        Byte[] outBytes = new byte[OutShort.Count * 2];
                        for (int b = 0; b < OutShort.Count; b++)
                            BitConverter.GetBytes(OutShort[b]).CopyTo(outBytes, b * 2);
                        AddParameterWithValue(sCmd, ":" + a.ToString(), outBytes);
                    }
                    else if (inValues[a] is CIM_RdfID)
                    {
                        byte[] inBytes = (inValues[a] as CIM_RdfID).GetBytes();
                        AddParameterWithValue(sCmd, ":" + a.ToString(), inBytes);
                    }
                    else if (inValues[a] is IEnumerable<CIM_Element>)
                    {
                        using (MemoryStream OutStream = new MemoryStream())
                        using (BinaryWriter bW = new BinaryWriter(OutStream))
                        {
                            foreach (CIM_Element Elem in (inValues[a] as IEnumerable<CIM_Element>))
                            {
                                bW.Write(Elem.Type);
                                bW.Write(Elem.ID);
                            }
                            bW.Flush();
                            AddParameterWithValue(sCmd, ":" + a.ToString(), OutStream.ToArray());
                        }
                    }

                    else if (inValues[a] is CIM_RdfID[])
                    {
                        List<Byte> outBytes = new List<byte>();
                        foreach (CIM_RdfID rdfID in inValues[a] as CIM_RdfID[])
                            outBytes.AddRange(rdfID.GetBytes());
                        AddParameterWithValue(sCmd, ":" + a.ToString(), outBytes.ToArray());
                    }
                    else
                        AddParameterWithValue(sCmd, ":" + a.ToString(), inValues[a]);
                return Convert.ToInt64(sCmd.ExecuteScalar());
            }
        }

        /// <summary>
        /// Mimic the AddWithValue function of Oracle and SqLite Command
        /// </summary>
        /// <param name="sCmd">The command</param>
        /// <param name="Name">The name of the parameter</param>
        /// <param name="Value">The value of the parameter</param>
        private static void AddParameterWithValue(DbCommand sCmd, String Name, Object Value)
        {
            DbParameter OutParam = sCmd.CreateParameter();
            OutParam.ParameterName = Name;
            OutParam.Value = Value;
            sCmd.Parameters.Add(OutParam);
        }


    }
}
